package com.panda.web.utils;

import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Base64;
import java.util.Comparator;

@Component
public class WXBizMsgCrypt {
    private static final String AES = "AES";
    private static final String AES_CBC_PKCS7 = "AES/CBC/PKCS5Padding";
    private static final String token = "MyWechatToken626"; // 替换为实际Token
    private static final String appId = "wx83de228493c38c1c"; // 替换为实际AppID
    private static final String encodingAESKey = "W2voVMYieyTVjzp7HysnAvEFWnw3r1SYNXvZpVidZiZ"; // 替换为实际AppSecret


    /**
     * 解密微信消息
     */
    public String decryptMsg(String msgSignature, String timestamp,
                             String nonce, String encryptMsg) throws Exception {
        // === 1. 准备参数 ===
        String[] arr = new String[]{token, timestamp, nonce, encryptMsg};

        // === 2. 关键修正：严格字典序排序（字符串比较）===
        Arrays.sort(arr, (s1, s2) -> s1.compareTo(s2));

        // === 3. 调试输出 ===
        System.out.println("=== 签名计算参数 ===");
        System.out.println("Token: " + token);
        System.out.println("Timestamp: " + timestamp);
        System.out.println("Nonce: " + nonce);
        System.out.println("EncryptMsg头尾: " + encryptMsg.substring(0, 10) + "..." + encryptMsg.substring(encryptMsg.length()-10));
        System.out.println("排序后参数: " + Arrays.toString(arr));

        // === 4. 计算签名 ===
        String joined = String.join("", arr);
        String calSignature = DigestUtils.sha1Hex(joined);
        System.out.println("计算签名: " + calSignature);
        System.out.println("微信签名: " + msgSignature);

        // === 5. 验证签名 ===
        if (!calSignature.equals(msgSignature)) {
            throw new Exception(String.format(
                    "签名验证失败！\n" +
                            "正确拼接方式：%s + %s + %s + %s\n" +
                            "当前计算结果：%s",
                    arr[0], arr[1], arr[2], arr[3], calSignature
            ));
        }

        // 2. Base64解码
        byte[] aesKey = Base64.getDecoder().decode(encodingAESKey + "=");
        byte[] encrypted = Base64.getDecoder().decode(encryptMsg);

        // 3. AES解密
        SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
        IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
        byte[] original = cipher.doFinal(encrypted);

        // 4. 处理解密结果
        byte[] bytes = PKCS7Encoder.decode(original);
        byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
        int xmlLength = bytesNetworkOrder2Number(networkOrder);

        String xmlContent = new String(
                Arrays.copyOfRange(bytes, 20, 20 + xmlLength),
                StandardCharsets.UTF_8
        );
        String fromAppId = new String(
                Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
                StandardCharsets.UTF_8
        );

        if (!fromAppId.equals(appId)) {
            throw new Exception("AppID校验失败");
        }

        System.out.println("解密成功:\n" + xmlContent);
        return xmlContent;
    }

    // 辅助方法
    private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) {
        return (bytesInNetworkOrder[3] & 0xFF) << 24 |
                (bytesInNetworkOrder[2] & 0xFF) << 16 |
                (bytesInNetworkOrder[1] & 0xFF) << 8 |
                (bytesInNetworkOrder[0] & 0xFF);
    }

    static class PKCS7Encoder {
        static byte[] decode(byte[] decrypted) {
            int pad = decrypted[decrypted.length - 1];
            return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
        }
    }

}